package blacklist

import (
	"sync"

	"github.com/libp2p/go-libp2p-core/peer"
	"hundsun.com/hsl/hschain/common/log/logging"
	"hundsun.com/hsl/hschain/p2p/impl/dht/node/p2pdb"
	dbm "hundsun.com/hsl/hschain/store/db"
)

const (
	//Blacklist 黑名单列表
	Blacklist = "blacklist"
	//BlacklistTmp 临时黑名单
	BlacklistTmp = "blacklistTmp"
	//Whitelist 白名单
	Whitelist = "whitelist"
	//WhitelistTmp 临时白名单
	WhitelistTmp = "whitelistTmp"
)

//PeerManager peer管理
type PeerManager struct {
	blacklist       map[peer.ID]peer.AddrInfo
	blacklistTmp    map[peer.ID]peer.AddrInfo
	whitelist       map[peer.ID]peer.AddrInfo
	whitelistTmp    map[peer.ID]peer.AddrInfo
	enableTemporary bool
	p2pDb           *p2pdb.DbHandler
	mutex           *sync.RWMutex
	log             logging.Log
}

//Option 选项
type Option func(*PeerManager)

//Operation 自定义方法
type Operation func(info peer.AddrInfo)

//Iterator 迭代
func (e *PeerManager) Iterator(listName string, op Operation) {
	switch listName {
	case Blacklist:
		e.iterator(e.blacklist, op)
	case BlacklistTmp:
		e.iterator(e.blacklistTmp, op)
	case Whitelist:
		e.iterator(e.whitelist, op)
	case WhitelistTmp:
		e.iterator(e.whitelistTmp, op)
	}
}

func (e *PeerManager) iterator(mp map[peer.ID]peer.AddrInfo, op Operation) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	for _, add := range mp {
		op(add)
	}
}

//EnableTemporary 是否启用临时黑名单
func EnableTemporary() Option {
	return func(p *PeerManager) {
		p.enableTemporary = true
	}
}

//AddSystemWhite AddSystemWhite
func AddSystemWhite(peerItems []peer.AddrInfo) Option {
	return func(p *PeerManager) {
		p.addSystemWhiteBatch(peerItems)
	}
}

//NewManager manager对象初始化
func NewManager(db *p2pdb.DbHandler, logger logging.Log, opts ...Option) (*PeerManager, error) {
	e := &PeerManager{}
	e.p2pDb = db
	e.blacklist = make(map[peer.ID]peer.AddrInfo)
	e.blacklistTmp = make(map[peer.ID]peer.AddrInfo)
	e.whitelist = make(map[peer.ID]peer.AddrInfo)
	e.whitelistTmp = make(map[peer.ID]peer.AddrInfo)
	e.enableTemporary = false
	e.mutex = &sync.RWMutex{}
	e.log = logger
	for _, opt := range opts {
		opt(e)
	}
	var peerInfos = make(map[peer.ID]peer.AddrInfo)
	var peerInfos2 = make(map[peer.ID]peer.AddrInfo)
	err := e.p2pDb.GetJSON(dbm.NamespaceP2pPeerInfo, &peerInfos)
	if err != nil {
		e.log.Warnf("init connected peers failed, reason:%v", err)
	}
	if len(peerInfos) != 0 {
		for _, item := range peerInfos {
			peerInfos2[item.ID] = item
		}
		e.log.Infof("init connected peers, peers:%v", peerInfos2)
		e.whitelistTmp = peerInfos2
	}
	return e, nil
}

//Store peerinfo持久化
func (e *PeerManager) Store() (int, error) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	//临时白名单列表保存数据库
	err := e.p2pDb.PutJSON(dbm.NamespaceP2pPeerInfo, e.whitelistTmp)
	if err != nil {
		return 0, err
	}
	e.log.Infof("store connected peers, peers:%v", e.whitelistTmp)
	return len(e.whitelistTmp), nil
}

//AddWhite 白名单加入
func (e *PeerManager) AddWhite(peerItem peer.AddrInfo) {
	//todo peer 异常判断
	e.mutex.Lock()
	defer e.mutex.Unlock()
	if _, ok := e.blacklist[peerItem.ID]; ok {
		return
	}
	delete(e.blacklistTmp, peerItem.ID)
	e.whitelistTmp[peerItem.ID] = peerItem
	e.log.Debugf("add connect peer temporary, peer:%v", peerItem)
}

//AddWhiteBatch 白名单批量加入
func (e *PeerManager) AddWhiteBatch(peerItems []peer.AddrInfo) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	e.mutex.Lock()
	defer e.mutex.Unlock()
	for _, peerItem := range peerItems {
		if _, ok := e.blacklist[peerItem.ID]; ok {
			return
		}
		delete(e.blacklistTmp, peerItem.ID)
		e.whitelistTmp[peerItem.ID] = peerItem
	}
}

func (e *PeerManager) addSystemWhiteBatch(peerItems []peer.AddrInfo) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	for _, peerItem := range peerItems {
		if _, ok := e.blacklist[peerItem.ID]; ok {
			return
		}
		e.whitelist[peerItem.ID] = peerItem
	}
}

func (e *PeerManager) addSystemWhite(peerItem peer.AddrInfo) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	if _, ok := e.blacklist[peerItem.ID]; ok {
		return
	}
	e.whitelist[peerItem.ID] = peerItem
}

//ContainsWhite 是否存在于白名单中
func (e *PeerManager) ContainsWhite(ID peer.ID) bool {
	e.mutex.RLock()
	defer e.mutex.RUnlock()
	_, ok1 := e.whitelist[ID]
	_, ok2 := e.whitelistTmp[ID]
	return ok1 || ok2
}

//IsConnectedPeer 是否是已连接节点
func (e *PeerManager) IsConnectedPeer(ID peer.ID) bool {
	e.mutex.RLock()
	defer e.mutex.RUnlock()
	_, ok2 := e.whitelistTmp[ID]
	return ok2
}

//DelWhite 白名单中删除
func (e *PeerManager) DelWhite(ID peer.ID) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	delete(e.whitelistTmp, ID)
}

func (e *PeerManager) delWhiteSystem(ID peer.ID) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	delete(e.whitelist, ID)
}

//Add 加入黑名单
func (e *PeerManager) Add(ID peer.ID) bool {
	return true
}

//AddBlack 加入黑名单
func (e *PeerManager) AddBlack(peerItem peer.AddrInfo) {
	if !e.enableTemporary {
		return
	}
	e.mutex.Lock()
	defer e.mutex.Unlock()
	if _, ok := e.whitelist[peerItem.ID]; ok {
		return
	}
	e.blacklistTmp[peerItem.ID] = peerItem
}

//AddBatch 批量加入黑名单
func (e *PeerManager) AddBatch(peerItems []peer.AddrInfo) {
	if !e.enableTemporary {
		return
	}
	e.mutex.Lock()
	defer e.mutex.Unlock()
	for _, peerItem := range peerItems {
		if _, ok := e.whitelist[peerItem.ID]; ok {
			return
		}
		e.blacklistTmp[peerItem.ID] = peerItem
	}
}

func (e *PeerManager) addSystemBatch(peerItems []peer.AddrInfo) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	for _, peerItem := range peerItems {
		if _, ok := e.whitelist[peerItem.ID]; ok {
			return
		}
		e.blacklist[peerItem.ID] = peerItem
	}
}

func (e *PeerManager) addSystem(peerItem peer.AddrInfo) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	if _, ok := e.whitelist[peerItem.ID]; ok {
		return
	}
	e.blacklist[peerItem.ID] = peerItem
}

//Contains 是否在黑名单中
func (e *PeerManager) Contains(ID peer.ID) bool {
	e.mutex.RLock()
	defer e.mutex.RUnlock()
	_, ok := e.blacklist[ID]
	_, ok2 := e.blacklistTmp[ID]
	return ok || ok2
}

//Del 黑名单中删除
func (e *PeerManager) Del(ID peer.ID) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	delete(e.blacklistTmp, ID)
}

func (e *PeerManager) delSystem(ID peer.ID) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	delete(e.blacklist, ID)
}
